﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static SimpleExec.Command;

namespace BridgeManager
{
    class PortParams : Dictionary<string, string>
    {
        public PortParams() { }
        public PortParams(string str)
        {
            char[] separator ={ ','};
            string[] prms = str.Split(separator, StringSplitOptions.RemoveEmptyEntries);
            
            for (int i = 0; i < prms.Length; i++)
            {
                char[] sep =  {'='};
                string[] prm = prms[i].Split(sep, StringSplitOptions.RemoveEmptyEntries);
                if (prm.Length == 2)
                {
                    this[prm[0].ToLower()] = prm[1].ToUpper();
                }
            }
        }
    }

    class PortPair
    {
        public PortParams portA;
        public PortParams portB;
        public string key;
        private int portNum;

        public PortPair()
        {
            portA = new PortParams();
            portB = new PortParams();
        }

        public PortPair(int num)
        {
            portA = new PortParams();
            portB = new PortParams();
            portNum = num;
        }

        public PortPair(string[] lines)
        {
            foreach (string line in lines)
            {
                char[] sep = { ' ' };
                string[] fields = line.Split(sep, StringSplitOptions.RemoveEmptyEntries);
                if (fields.Length != 2)
                    continue;

                if (fields[0].StartsWith("CNCA"))
                {
                    key = fields[0].Substring(4);
                    portA = new PortParams(fields[1]);

                    portNum = int.Parse(key);
                }
                else if (fields[0].StartsWith("CNCB"))
                {
                    key = fields[0].Substring(4);
                    portB = new PortParams(fields[1]);

                    portNum = int.Parse(key);
                }
            }
        }

        public int GetNum()
        {
            return portNum;
        }

        public void SetNum(int portNum)
        {
            this.portNum = portNum;
        }

        public PortParams Get(int i)
        {
            if (i == 0)
                return portA;
            else
                return portB;
        }
        
        public void Set(int i, PortParams port)
        {
            if (i == 0)
                portA = port;
            else
                portB = port;
        }
    }

    class PortPairs: Dictionary<string , PortPair>
    {
        public PortPairs()
        {
            string result = ExecCmd("--detail-prms list");
            string[] lines = result.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string line in lines) {
                string[] fields = line.Split(new char[] { ' '}, StringSplitOptions.RemoveEmptyEntries);
                if (fields.Length != 2)
                    continue;

                int iPort;
                if (fields[0].StartsWith("CNCA"))
                    iPort = 0;
                else if (fields[0].StartsWith("CNCB"))
                    iPort = 1;
                else
                    continue;

                string pairNum = fields[0].Substring(4);
                if (!ContainsKey(pairNum))
                    this[pairNum] = new PortPair(int.Parse(pairNum));

                this[pairNum].Set(iPort, new PortParams(fields[1]));
            }
        }

        private void LoadPortPairs()
        {
            string result = ExecCmd("--detail-prms list");
            string[] lines = result.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string line in lines)
            {
                string[] fields = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (fields.Length != 2)
                    continue;

                int iPort;
                if (fields[0].StartsWith("CNCA"))
                    iPort = 0;
                else if (fields[0].StartsWith("CNCB"))
                    iPort = 1;
                else
                    continue;

                string pairNum = fields[0].Substring(4);
                if (!ContainsKey(pairNum))
                    this[pairNum] = new PortPair(int.Parse(pairNum));

                this[pairNum].Set(iPort, new PortParams(fields[1]));
            }
        }

        public PortPair CreatePortPair()
        {
            string result = ExecCmd(string.Format("--wait 30 --detail-prms install PortName=COM# HiddenMode=yes"));
            string[] lines = result.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            PortPair portPair = new PortPair(lines);
            string pairNum = portPair.GetNum().ToString();

            while (true)
            {
                LoadPortPairs();

                if (this.ContainsKey(pairNum)) {
                    portPair = this[pairNum];
                    if (portPair.portA.ContainsKey("realportname"))
                        return portPair;
                }
            }
        }

        public void RemovePair(int portNum)
        {
            string cmd = string.Format("remove {0}", portNum);
            string result = ExecCmd(cmd);
        }

        public void RemovePair(string realPortName)
        {
            foreach (PortPair pair in this.Values)
            {
                if (!pair.portA.ContainsKey("realportname"))
                    continue;

                if (pair.portA["realportname"] == realPortName)
                    RemovePair(pair.GetNum());
            }
        }

        public bool IsValidName(string name)
        {
            string result = ExecCmd("busynames *");
            string[] busyNames = result.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            foreach(string busyName in busyNames) {
                if (busyName.ToUpper() == name.ToUpper())
                    return false;
            }

            return true;
        }

        public string GetFreeComName()
        {
            string result = ExecCmd("busynames *");
            string[] busyNames = result.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 1; i < 256; i++)
            {
                string name = "COM" + i.ToString();
                if (!busyNames.Contains(name))
                    return name;
            }

            throw new Exception("invalid COM name");
        }

        private string ExecCmd(string cmd)
        {
            string result = string.Empty;
            try
            {
                string setupc_path = @"C:\\Program Files (x86)\\com0com\\setupc.exe";
                result = Read(setupc_path, cmd, null, false,
                            null,
                            null,
                            null,
                            null,
                            true
                            );
            }
            catch
            {
                Console.WriteLine("error\n");
            }


            return result;
        }
    }
}
